﻿
using DoNetDrive.Core;
using DoNetDrive.Core.Connector;
using DoNetDrive.Core.Connector.TCPClient;
using DotNetty.Buffers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.WebSockets;
using System.Text;
using System.Threading.Tasks;

namespace DoNetDrive.AspWebSocke.WebSocketServer
{
    public class WebSocketServerConnector : AbstractConnector
    {
        protected int DefaultReadDataBufferSize = 2048;
        protected System.Net.WebSockets.WebSocket _Client;
        protected int _ConnectTimeoutMSEL;
        protected int _ReconnectMax;
        protected int _ReconnectCount;
        public WebSocketServerConnector(WebSocketServerClientDetail detail)
        {
            SetConnectOption(detail);
            _ReconnectCount = 0;
            _ConnectorDetail = detail;

            _Client = detail.Client;
            _Status = WebSocketServerConnectorStatus.Connected;
            _IsForcibly = true;
            _IsActivity = true;
        }
        private void SetConnectOption(WebSocketServerClientDetail detail)
        {
            _ConnectTimeoutMSEL = detail.Timeout;
            _ReconnectMax = detail.RestartCount;
            if (_ConnectTimeoutMSEL > TCPClientFactory.CONNECT_TIMEOUT_MILLIS_MAX)
                _ConnectTimeoutMSEL = TCPClientFactory.CONNECT_TIMEOUT_MILLIS_MAX;
            else if (_ConnectTimeoutMSEL < TCPClientFactory.CONNECT_TIMEOUT_MILLIS_MIN)
                _ConnectTimeoutMSEL = TCPClientFactory.CONNECT_TIMEOUT_MILLIS_MIN;
            if (_ReconnectMax > TCPClientFactory.CONNECT_RECONNECT_MAX)
                _ReconnectMax = TCPClientFactory.CONNECT_RECONNECT_MAX;
            else if (_ReconnectMax < 0)
                _ReconnectMax = 0;
        }
        public override string GetConnectorType()
        {
            return ConnectorType.WebSocketServer;
        }


        /// <summary>
        /// 接收数据
        /// </summary>
        /// <returns></returns>
        protected async virtual Task ReceiveAsync()
        {
            try
            {
                SetConnectOptionByDefault();
                var buffer = new byte[DefaultReadDataBufferSize];
                IByteBuffer NettyBuf = null;
                WebSocketReceiveResult result;
                int len = 0;
                FireClientOnline(this);
                while (true)
                {
                    result = await _Client.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
                    if (result.CloseStatus.HasValue) break;
                    if (NettyBuf == null)
                    {
                        NettyBuf = GetByteBufAllocator().Buffer();
                    }
                    NettyBuf.WriteBytes(buffer);
                    len += result.Count;
                    if (result.EndOfMessage)
                    {
                        NettyBuf.SetWriterIndex(result.Count);
                        ReadByteBuffer(NettyBuf);
                        NettyBuf.Release();
                        NettyBuf = null;
                    }

                }
            }
            catch (WebSocketException ex)
            {
                Console.WriteLine("连接发生错误:" + ex.Message);
            }
            FireClientOffline(this);
        }
        protected override INConnectorStatus GetInitializationStatus()
        {
            return WebSocketServerConnectorStatus.Closed;
        }
        /// <summary>
        /// 设置连接默认值
        /// </summary>
        protected void SetConnectOptionByDefault()
        {
            _ConnectTimeoutMSEL = TCPClientFactory.CONNECT_TIMEOUT_Default;
            _ReconnectMax = TCPClientFactory.CONNECT_RECONNECT_Default;
        }
        /// <summary>
        /// 写入数据
        /// </summary>
        /// <param name="buf"></param>
        /// <returns></returns>
        protected override async Task WriteByteBuf0(IByteBuffer buf)
        {
            await WriteBinary(buf);
        }

        private async Task WriteByteBuf(IByteBuffer buf, WebSocketMessageType messageType)
        {
            if (CheckIsInvalid())
            {
                await Task.FromException(new Exception($"connect is {_Status.Status}"));
            }
            if (_Client != null && _Client.State == WebSocketState.Open)
            {
                await _Client.SendAsync(new ArraySegment<byte>(buf.Array, buf.ArrayOffset, buf.ReadableBytes), messageType, true, CancellationToken.None);
            }
            buf.Release();
        }
        private async Task WriteBinary(IByteBuffer buffer)
        {
            await WriteByteBuf(buffer, WebSocketMessageType.Binary);
        }

        private async Task WriteText(IByteBuffer buffer)
        {
            await WriteByteBuf(buffer, WebSocketMessageType.Text);
        }
        /// <summary>
        /// 检查连接超时
        /// </summary>
        public virtual void CheckConnectorTimeout()
        {
            if (_Status.Status().Equals("Connecting"))
            {
                return;
            }
            var lTime = (DateTime.Now - _ConnectDate).TotalMilliseconds;
            try
            {
                if (lTime > _ConnectTimeoutMSEL)
                {
                    ConnectFail(new TimeoutException($"Connect {RemoteAddress()} Timeout"));
                }
                else
                {
                    UpdateActivityTime();
                }

            }
            catch
            {
                if (_Client != null)
                {
                    _Client.Dispose();
                }
                _Client = null;
            }
        }
        /// <summary>
        /// 连接失败
        /// </summary>
        /// <param name="ex"></param>
        public virtual void ConnectFail(Exception ex)
        {
            if (ex is ObjectDisposedException ||
                _Status.Status().Equals("Invalid"))
            {
                return;
            }
            _IsActivity = false;
            if (_ReconnectCount > _ReconnectMax)
            {
                if (_IsForcibly)
                {
                    _ReconnectCount = 0;
                    _Status = WebSocketServerConnectorStatus.Closed;
                }
                else
                {
                    _ConnectorDetail.SetError(new Exception("已达到最大重试次数", ex));
                    FireConnectorErrorEvent(_ConnectorDetail);
                    SetInvalid();
                }
            }
            else
            {
                _Status = WebSocketServerConnectorStatus.Closed;
            }
        }
        /// <summary>
        /// 检查连接状态
        /// </summary>
        public virtual void CheckConnectedStatus()
        {
            if (!CheckIsInvalid())
            {
                if (_CommandList.Count > 0)
                    CheckCommandList();
            }
        }
        /// <summary>
        /// 关闭联系
        /// </summary>
        /// <returns></returns>
        public override async Task CloseAsync()
        {
            if (_isRelease || (!_IsActivity))
                return;
            _Status = ConnectorStatus.Invalid;
            try
            {
                if (_Client != null && _Client.State == WebSocketState.Open)
                    await _Client.CloseAsync(WebSocketCloseStatus.Empty, "", CancellationToken.None);
            }
            catch (Exception ex)
            {
                _ConnectorDetail.SetError(ex);
            }
            _Client = null;
            UpdateActivityTime();
            FireConnectorClosedEvent(_ConnectorDetail);
            SetInvalid();
            _IsForcibly = false;
        }
        /// <summary>
        /// 释放资源
        /// </summary>
        protected override void Release0()
        {
        }

        public override async Task ConnectAsync()
        {

            await ReceiveAsync();
        }

        public void ConnectingNext(Task connTask)
        {
            if (CheckIsInvalid()) return;
            if (!_Status.Status().Equals("Connecting")) return;
            if (_Client == null) return;
            if (connTask.IsFaulted || connTask.IsCanceled)
            {
                ConnectFail(connTask.Exception);
            }
        }

        public override IPDetail LocalAddress()
        {
            return default;
        }

        public override IPDetail RemoteAddress()
        {
            return default;
        }

    }
}
